package cn.schoolwow.quickapi.module.common.flow;

import cn.schoolwow.quickapi.domain.QuickAPIOption;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.util.domain.query.reflection.QueryReflection;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

public class GetFieldValueObjectFlow implements BusinessFlow {
    private Logger logger = LoggerFactory.getLogger(GetFieldValueObjectFlow.class);

    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        String fieldTypeName = flowContext.checkData("fieldTypeName", String.class);
        List<String> javaTypeList = flowContext.getData("javaTypeList", List.class, new ArrayList());

        String javaType = fieldTypeName;
        String genericType = null;
        if(fieldTypeName.contains("<")){
            javaType = fieldTypeName.substring(0, fieldTypeName.indexOf("<"));
            genericType = fieldTypeName.substring(fieldTypeName.indexOf("<")+1, fieldTypeName.lastIndexOf(">"));
        }

        if(javaType.startsWith("sun.")
                ||javaType.startsWith("java.lang.reflect")
                ||javaType.equalsIgnoreCase("T")
                ||javaType.equalsIgnoreCase("java.lang.Object")
        ){
            return;
        }

        if(isEntityPackageName(flowContext)){
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Class clazz = null;
            try {
                clazz = classLoader.loadClass(fieldTypeName);
            }catch (Exception e){
                logger.warn("类加载器加载类失败!类名:"+fieldTypeName+",原因:"+e.getMessage());
                return;
            }
            javaTypeList.add(javaType);
            List<Field> fieldList = QueryReflection.newQuery(clazz)
                    .execute()
                    .getFieldList();
            Object childInstance = clazz.getConstructor().newInstance();
            for(Field field:fieldList){
                String currentFieldTypeName = field.getGenericType().getTypeName();
                //判断是否存在循环依赖
                if(javaTypeList.contains(currentFieldTypeName)){
                    logger.warn("存在循环依赖!类名:"+currentFieldTypeName);
                    continue;
                }
                Object returnObject = flowContext.startFlow(new GetFieldValueObjectFlow())
                        .putCurrentCompositeFlowData("fieldTypeName", currentFieldTypeName)
                        .execute()
                        .getData("returnObject");
                field.set(childInstance, returnObject);
            }
            flowContext.putReturnData("returnObject", childInstance);
        }else{
            Object fieldValue = getValueByField(javaType, genericType, flowContext);
            flowContext.putReturnData("returnObject", fieldValue);
        }
    }

    @Override
    public String name() {
        return "模拟数据";
    }

    private boolean isEntityPackageName(FlowContext flowContext){
        String fieldTypeName = flowContext.checkData("fieldTypeName", String.class);
        QuickAPIOption quickAPIOption = flowContext.checkInstanceData(QuickAPIOption.class);

        for(String entityPackageName:quickAPIOption.entityPackageNameList){
            if(fieldTypeName.startsWith(entityPackageName)){
                return true;
            }
        }
        return false;
    }

    private Object getValueByField(String javaType, String genericType, FlowContext flowContext){
        switch (javaType){
            case "byte":
            case "java.lang.Byte":{return (byte)1;}
            case "boolean":
            case "java.lang.Boolean":{return true;}
            case "char":
            case "java.lang.Character":{return 'a';}
            case "short":
            case "java.lang.Short":{return (short)1;}
            case "int":
            case "java.lang.Integer":{return 1;}
            case "java.lang.Integer[]":{return new Integer[]{1,2,3};}
            case "float":
            case "java.lang.Float":{return (float)1.1;}
            case "long":
            case "java.lang.Long":{return 1L;}
            case "java.lang.Long[]":{return new Long[]{1L,2L,3L};}
            case "double":
            case "java.lang.Double":{return 1.1;}
            case "java.lang.String":{return "string";}
            case "java.lang.String[]":{return new String[]{"string1","string2","string3"};}
            case "java.util.Date":{return new Date();}
            case "java.sql.Date":{return new java.sql.Date(System.currentTimeMillis());}
            case "java.sql.Time":{return new Time(System.currentTimeMillis());}
            case "java.sql.Timestamp":{return new Timestamp(System.currentTimeMillis());}
            case "java.time.LocalDate":{return LocalDate.now();}
            case "java.time.LocalDateTime":{return LocalDateTime.now();}
            case "java.math.BigDecimal":{return BigDecimal.valueOf(1.23456f);}
            case "com.alibaba.fastjson.JSONObject":{
                JSONObject object = new JSONObject();
                object.put("key", "value");
                return object;
            }
            case "com.alibaba.fastjson.JSONArray":{
                JSONArray array = new JSONArray();
                JSONObject object = new JSONObject();
                object.put("key", "value");
                array.add(object);
                return array;
            }
            case "java.util.List":
            case "java.util.Set":{
                Object returnObject = null;
                if(null!=genericType){
                    returnObject = flowContext.startFlow(new GetFieldValueObjectFlow())
                            .putCurrentCompositeFlowData("fieldTypeName", genericType)
                            .execute()
                            .getData("returnObject");
                }
                switch (javaType){
                    case "java.util.List":{
                        List list = new ArrayList();
                        if(null!=returnObject){
                            list.add(returnObject);
                        }else{
                            list.add(new Object());
                        }
                        return list;
                    }
                    case "java.util.Set":{
                        Set set = new HashSet();
                        if(null!=returnObject){
                            set.add(returnObject);
                        }else{
                            set.add(new Object());
                        }
                        return set;
                    }
                }
            }break;
            case "java.util.Map":{
                Map map = new HashMap();
                String keyClassName = genericType.substring(0,genericType.indexOf(",")).trim();
                Object keyObject = flowContext.startFlow(new GetFieldValueObjectFlow())
                        .putCurrentCompositeFlowData("fieldTypeName", keyClassName)
                        .execute()
                        .getData("returnObject");
                String valueClassName = genericType.substring(genericType.indexOf(",")+1).trim();
                Object valueObject = flowContext.startFlow(new GetFieldValueObjectFlow())
                        .putCurrentCompositeFlowData("fieldTypeName", valueClassName)
                        .execute()
                        .getData("returnObject");
                map.put(keyObject, valueObject);
                return map;
            }
        }
        logger.warn("不支持的字段类型!类型:"+javaType);
        return null;
    }
}
